package com.demo.webapp.result;

import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.Writer;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang.StringUtils;
import org.apache.struts2.StrutsStatics;
import org.codehaus.jackson.JsonGenerationException;
import org.codehaus.jackson.map.JsonMappingException;
import org.codehaus.jackson.map.ObjectMapper;

import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.Result;

/**
 * 简单Json结果处理类
 * 对简单对象进行Json处理
 * @author ryuu.kk
 *
 */
public class SimpleJsonResult implements Result {

    private boolean enableGZIP = false;
    
    /**
     * 跨域jsonp的回调名称
     */
    private String jsonp = "callback";
	/**
	 * 版本序列化ID
	 */
	private static final long serialVersionUID = -7124105766588137592L;

	@Override
	public void execute(ActionInvocation invocation)  {
		
        boolean isJsonp = false;
        
		ActionContext actionContext = invocation.getInvocationContext();
        HttpServletRequest request = (HttpServletRequest) actionContext.get(StrutsStatics.HTTP_REQUEST);
        HttpServletResponse response = (HttpServletResponse) actionContext.get(StrutsStatics.HTTP_RESPONSE);
        
        String callback = actionContext.getValueStack().findString(jsonp);
        StringWriter writer = new StringWriter();

        if (StringUtils.isNotBlank(callback)){
        	//使用jsonp跨域访问
        	isJsonp = true;
        	writer.write(callback + "(");
        }
        //设置是JSON数据
      	String encoding = response.getCharacterEncoding();
      	preRender(response, encoding, "application/json; charset=" + encoding);
      		
      	Object rootObject;
        rootObject = readRootObject(invocation);
        PrintWriter out = null;
        try {
    		out = response.getWriter();
    		writeToResponse(writer, createJSONString(request, rootObject), enableGzip(request));
    		if (isJsonp) {
    			writer.write(");");
    		}
    		out.write(writer.getBuffer().toString());
    		
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			//直接关闭response流
			out.flush();
			out.close();
		}
	}

	private void writeToResponse(Writer out,
			Object createJSONString, Object enableGzip2) throws IOException {
		object2Json(createJSONString, out);
	}

	protected void object2Json(Object result, Writer out) throws IOException {
		ObjectMapper mapper = new ObjectMapper();
		
		try {
			mapper.writeValue(out, result);
		} catch (JsonGenerationException e) {
			e.printStackTrace();
		} catch (JsonMappingException e) {
			e.printStackTrace();
		} 
	}
	
	private Object enableGzip(HttpServletRequest request) {
		String header = request.getHeader("Accept-Encoding");
	    return enableGZIP && (header != null) && (header.indexOf("gzip") >= 0);
	}

	private Object readRootObject(ActionInvocation invocation) {
		Object action = invocation.getAction();
		Object result = null;
		if (action instanceof RenderResult) {
			result = ((RenderResult) action).getResult();
		}
		return result;
	}

	private Object createJSONString(HttpServletRequest request, Object rootObject) {
		
		return rootObject;
	}
	
	private void preRender(HttpServletResponse response, String encoding, String contentType) {
		response.setCharacterEncoding(encoding);
    	response.setHeader("Content-Language", encoding);
    	response.setContentType(contentType);
    	response.setHeader("Pragma", "no-cache");
    	response.setHeader("cache-control", "no-cache");
    	response.setHeader("Expires", "Thu, 01 Jan 1970 00:00:00 GMT");
	}
	
	public void setEnableGZIP(boolean enableGZIP) {
		this.enableGZIP = enableGZIP;
	}

	public void setJsonp(String jsonp) {
		this.jsonp = jsonp;
	}
}
